#! /usr/bin/env python
"""
Genetic Algorithm optimization for the OpenAssembly Adaptive Platform
OpenAssembly Specific
"""

from pygene.gene import BaseGene
from pygene.organism import MendelOrganism
from pygene.population import Population
from celery.task import task
import models
import random


def openassembly_adaptive_platform(website, pop=10, nkids=40,
                                        platform_type='policy'):

    #storage for all possible genes and local fitness of those genes
    fitnii = {}

    #get initial set of all possible genes
    users = models.get_item(website, 'user', data=None)
    for u in users:
        try:
            platform = u['platforms'][platform_type]
            for plank in platform:
                fitnii[plank] = None
        except:
            #user has no declared platform
            pass

    def fitness_function():
        pass

    @task
    def get_fitness(obj_pk):
        #returns community preference for this object
        fit = fitnii[obj_pk]
        if fit == None:
            pass


    @task
    def comp(thisvalue, othervalue):
        #get's fitness of OA platform based on community preference
        tv = get_fitness(thisvalue)
        ov = get_fitness(thisvalue)
        if tv >= ov:
            return thisvalue
        else:
            return othervalue

    @task
    def random_gene(obj_pk, website):
        random.choice(fitnii.keys())

    class PlankGene(BaseGene):
        mutProb = 0.1
        mutAmt = 2

        def __init__(self, value=None):
            self.value = random_gene()

        def __add__(self, other):
            return comp(self.value, other.value)

        def mutate(self):
            self.value = random_gene()

        def randomValue(self):
            return random_gene()

    ###OA PLATFORM Configuration Information
    platform_size = 10

    # generate a genome, one gene for each char in the string
    genome = {}
    for i in range(platform_size):
        genome[str(i)] = PlankGene

    class AdaptivePlatform(MendelOrganism):
    # an organism that evolves towards optimal platform
        genome = genome

        def __repr__(self):
            """
            Return the gene values as a string
            """

            chars = []
            for k in xrange(self.numgenes):
                c = self[str(k)]
                chars.append(c)

            return ''.join(chars)

        def fitness(self):
            """
            calculate fitness, as the sum of the squares
            of the distance of each char gene from the
            corresponding char of the target string
            """
            fit = 0
            for i in xrange(self.numgenes):
                obj_id = self[str(i)]
                obj_fit = get_fitness(obj_id)
                fit += obj_fit

            return fit

    class PlatformPopulation(Population):

        initPopulation = pop
        species = AdaptivePlatform

        # cull to this many children after each generation
        childCull = 10
        # number of children to create after each generation
        childCount = nkids

    # start with a population of 10 random organisms
    ph = PlatformPopulation()

    i = 0
    prev_utility = 0
    epsilon = .05
    stop_trying = 5
    itr = 0
    utility = 10000
    while stop_trying > itr:
        if abs(utility - prev_utility) > epsilon:
            itr = 0
        else:
            itr += 1
        b = ph.best()
        print "generation %s: %s best=%s average=%s)" % (
            i, str(b), b.fitness(), ph.fitness())
        prev_utility = utility
        utility = b.fitness()
        i += 1
        ph.gen()
